﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Extentions;
using TrainingReminderSystem.Model;
using TrainingReminderSystem.Dal;
using Senparc.Weixin.Open.OAuthAPIs;

namespace TrainingReminderSystem.Bll
{
    /// <summary>
    /// 员工OpenID 逻辑层
    /// </summary>
    public partial class SysCustomerOpenIDBll : CustomerLoginedBll
    {
        #region 创建token信息

        /// <summary>
        /// 创建token信息
        /// </summary>
        /// <param name="openID"></param>
        /// <returns></returns>
        public static string CreateWechatToken(SysCustomerOpenID openID)
        {
            string val =
                $"{openID.ID}{TokenSplit}{openID.OpenID}{TokenSplit}{(int)openID.EnumOpenIDType}{TokenSplit}{(openID.session_Key ?? string.Empty)}{TokenSplit}{openID.SysStoreID}{TokenSplit}{(int)SysConfig.EnumRunProject}{TokenSplit}{WechatCustomerTokenKey}{TokenSplit}{DateTime.Now.ExToLong()}";
            string token = openID.ID + TokenSplit + Extentions.DEncryptHelper.Encrypt(val);
            return token;
        }

        #endregion

        #region 获取token并自动登录,验证token并自动登录

        /// <summary>
        /// 获取token并自动登录,验证token并自动登录
        /// </summary>
        /// <param name="userInfo"></param>
        /// <param name="type"></param>
        /// <param name="wechatToken"></param>
        /// <param name="session_Key">小程序的session_Key</param>
        /// <param name="withCache">是否有缓存</param>
        /// <returns>Message是WechatToken;Result是Token登录信息</returns>
        public static AjaxResult<List<CustomerLoginInfo>> GetWechatToken(Senparc.Weixin.Open.OAuthAPIs.OAuthUserInfo userInfo,
            EnumOpenIDType type, string wechatToken, string session_Key, bool withCache = true)
        {
            if (userInfo == null || string.IsNullOrWhiteSpace(userInfo.openid))
            {
                return AjaxResult<List<CustomerLoginInfo>>.ErrorResult("没有获取到OPENID值");
            }

            try
            {
                using var db = DbNoFilter;
                SysCustomerOpenID currentOpenID = db.SysCustomerOpenID.Include(m => m.SysStore).AsNoTracking()
                    .FirstOrDefault(m => m.OpenID == userInfo.openid && m.EnumOpenIDType == type);
                if (currentOpenID == null)
                {
                    return AjaxResult<List<CustomerLoginInfo>>.ErrorResult("没有找到相关OPENID信息");
                }
                if (currentOpenID.SysStore == null || currentOpenID.SysStore.EnumStatus != EnumStatus.启用)
                {
                    return AjaxResult<List<CustomerLoginInfo>>.ErrorResult("没有找到相关店铺信息");
                }
                SysCustomerOpenID cacheOpenID = CurrentOpenID;
                if (string.IsNullOrEmpty(session_Key))
                {
                    session_Key = cacheOpenID != null ? cacheOpenID.session_Key : null;
                }
                currentOpenID.session_Key = session_Key;
                if (string.IsNullOrWhiteSpace(wechatToken))
                {
                    wechatToken = cacheOpenID != null ? cacheOpenID.WechatToken : null;
                    if (string.IsNullOrWhiteSpace(wechatToken))
                    {
                        wechatToken = CreateWechatToken(currentOpenID);
                    }
                }
                currentOpenID.WechatToken = wechatToken;

                //设置OpenID
                if (withCache)
                {
                    if (string.IsNullOrWhiteSpace(WechatToken))
                    {
                        WechatToken = wechatToken;
                    }
                    SetCurrentOpenID(wechatToken, currentOpenID);
                }

                List<CustomerLoginInfo> result = null;
                if (currentOpenID.SysCustomerID != null)
                {
                    //拉出用户Token
                    int id = currentOpenID.SysCustomerID.Value;
                    AjaxResult<List<CustomerLoginInfo>> ar =
                        new SysCustomerBll().LoginBase(m => m.SysCustomerID == id, null, Token, wechatToken, db, withCache);
                    if (!ar.Success)
                    {
                        return AjaxResult<List<CustomerLoginInfo>>.ErrorResult(ar.Message);
                    }
                    if (ar.Result.Count > 0)
                    {
                        result = ar.Result;
                    }
                }
                else
                {
                    try
                    {
                        if (!string.IsNullOrEmpty(currentOpenID.WxJson))
                        {
                            var userInfo2 = JsonHelper.DeserializeObject<OAuthUserInfo>(currentOpenID.WxJson);
                            if (userInfo2 != null) userInfo = userInfo2;
                        }
                    }
                    catch (Exception ex)
                    {
                    }

                    var store = currentOpenID.SysStore;
                    CustomerLoginInfo loginInfo = new CustomerLoginInfo()
                    {
                        WechatToken = wechatToken,

                        Token = null,
                        UserName = !string.IsNullOrEmpty(userInfo.nickname) ? userInfo.nickname : currentOpenID.nickname,
                        UserHeader = !string.IsNullOrEmpty(userInfo.headimgurl) ? userInfo.headimgurl : currentOpenID.headimgurl,

                        SysCustomerID = 0,
                        SysStoreID = currentOpenID.SysStoreID,
                        SysStoreName = store?.SysStoreName,

                        IsDemo = true,
                        CreateDate = DateTime.Now,

                        EnumSysCustomerType = (EnumSysCustomerType)0
                    };
                    result = new List<CustomerLoginInfo>()
                    {
                        loginInfo
                    };
                }

                var r = AjaxResult<List<CustomerLoginInfo>>.SuccessResult(result, currentOpenID.session_Key);
                return r;
            }
            catch (Exception ex)
            {
                ex.ExLogError("GetWechatToken报错");
                return AjaxResult<List<CustomerLoginInfo>>.ErrorResult("获取OpenID出错");
            }
        }

        //public static string GetToken()
        //{
        //    var customerOpenID = SysCustomerOpenID;
        //    if (customerOpenID == null)
        //    {
        //        if (!string.IsNullOrEmpty(ChezhuLoginBll.Token))//执行下验证方法,又怕重复执行,写入了个60秒的缓存
        //        {
        //            string cacheKey = ChezhuLoginBll.Token + "_ValidateCache";
        //            AjaxResult<string> cache = CacheHelper.GetCache(cacheKey) as AjaxResult<string>;
        //            if (cache == null)
        //            {
        //                cache = Validate();
        //                CacheHelper.SetAbsoluteCache(cacheKey, cache, 10);
        //                if (cache.Success)
        //                {
        //                    return cache.Result;
        //                }
        //            }
        //        }

        //        return string.Empty;
        //    }
        //    var userInfo = new Senparc.Weixin.Open.OAuthAPIs.OAuthUserInfo();
        //    userInfo.openid = customerOpenID.OpenID;
        //    var r = GetToken(userInfo, customerOpenID.EnumOpenIDType, ChezhuLoginBll.Token);
        //    return r.Result;
        //}

        /// <summary>
        /// 没有此openID,也会返回true
        /// </summary>
        /// <returns></returns>
        public static AjaxResult<List<CustomerLoginInfo>> LoginByToken()
        {
            string wechatToken = WechatToken;
            if (string.IsNullOrEmpty(wechatToken))
            {
                return AjaxResult<List<CustomerLoginInfo>>.SuccessResult();
            }
            var r = new AjaxResult<List<CustomerLoginInfo>>();
            //有token解析他,他有具体是某一个帐号的
            var tempArray = wechatToken.Split(TokenSplit);
            var encrypt = tempArray.Length > 1 ? tempArray[1] : null;
            if (string.IsNullOrEmpty(encrypt))
            {
                //r.Message = "token格式错误";
                return r;
            }
            string val = DEncryptHelper.Decrypt(encrypt);
            if (string.IsNullOrEmpty(val))
            {
                //r.Message = "token格式错误";
                return r;
            }
            var arr = val.Split(TokenSplit);
            if (arr.Length < 6)
            {
                //r.Message = "token格式错误";
                return r;
            }
            int id = arr[0].ExToInt32();
            if (id <= 0)
            {
                //r.Message = "token格式错误";
                return r;
            }
            if (tempArray[0].ExToInt32() != id)
            {
                //r.Message = "token格式错误";
                return r;
            }
            //店铺ID
            int sysStoreID = arr[4].ExToInt32();
            if (sysStoreID <= 0)
            {
                //r.Message = "token格式错误";
                return r;
            }

            string openID = arr[1];
            EnumOpenIDType type = (EnumOpenIDType)arr[2].ExToInt32();
            DateTime dt = arr[arr.Length - 1].ExToDateTime();
            if (dt.Date < DateTime.Now.AddDays(-3).Date)
            {
                //r.Message = "token过期";
                return r;
            }

            string session_Key = arr[3];
            var userInfo = new Senparc.Weixin.Open.OAuthAPIs.OAuthUserInfo();
            userInfo.openid = openID;
            return GetWechatToken(userInfo, type, wechatToken, session_Key);
        }

        #endregion

        #region 绑定和解绑的操作

        public static void Bind(int id)
        {
            if (CurrentOpenID != null && CurrentOpenID.SysCustomerID != id)
            {
                using var db = PcLoginedBll.DbNoFilter;
                Bind(id, db);
            }
        }

        /// <summary>
        /// 绑定
        /// </summary>
        /// <param name="id"></param>
        /// <param name="db"></param>
        internal static void Bind(int id, DbEntities db)
        {
            if (CurrentOpenID != null && CurrentOpenID.SysCustomerID != id)
            {
                string sql =
                    $"update {nameof(SysCustomerOpenID)} set {nameof(SysCustomerOpenID.SysCustomerID)}={id} where {nameof(SysCustomerOpenID.ID)}={CurrentOpenID.ID}";
                db.Database.ExExecuteSqlCommand(sql);
                CurrentOpenID.SysCustomerID = id;
                SetCurrentOpenID(WechatToken, CurrentOpenID);
            }
        }

        /// <summary>
        /// 解绑
        /// </summary>
        /// <param name="db"></param>
        /// <exception cref="NotImplementedException"></exception>
        internal static void UnBind(DbEntities db)
        {
            if (CurrentOpenID != null)
            {
                string sql =
                    $"update {nameof(SysCustomerOpenID)} set {nameof(SysCustomerOpenID.SysCustomerID)}=null where {nameof(SysCustomerOpenID.ID)}={CurrentOpenID.ID}";
                db.Database.ExExecuteSqlCommand(sql);
                CurrentOpenID.SysCustomerID = null;
                SetCurrentOpenID(WechatToken, CurrentOpenID);

                SetCurrentCustomer(Token, null);
            }
        }

        public static void BindWithUnionid(int id)
        {
            if (CurrentOpenID != null)
            {
                using var db = PcLoginedBll.DbNoFilter;
                BindWithUnionid(id, db);
            }
        }

        /// <summary>
        /// 绑定
        /// </summary>
        /// <param name="id"></param>
        /// <param name="db"></param>
        internal static void BindWithUnionid(int id, DbEntities db)
        {
            var currentOpenID = CurrentOpenID;
            if (currentOpenID != null && !string.IsNullOrEmpty(currentOpenID.unionid))
            {
                string sql =
                    $"update {nameof(SysCustomerOpenID)} set {nameof(SysCustomerOpenID.SysCustomerID)}={id} where {nameof(SysCustomerOpenID.unionid)}='{currentOpenID.unionid.ExClearSql()}' and {nameof(SysCustomerOpenID.SysStoreID)}={currentOpenID.SysStoreID}";
                db.Database.ExExecuteSqlCommand(sql);
                currentOpenID.SysCustomerID = id;
                SetCurrentOpenID(WechatToken, CurrentOpenID);
            }
            else
            {
                Bind(id, db);
            }
        }

        /// <summary>
        /// 解绑
        /// </summary>
        /// <param name="db"></param>
        /// <exception cref="NotImplementedException"></exception>
        internal static void UnBindWithUnionid(DbEntities db)
        {
            var currentOpenID = CurrentOpenID;
            if (currentOpenID != null && !string.IsNullOrEmpty(currentOpenID.unionid))
            {
                string sql =
                    $"update {nameof(SysCustomerOpenID)} set {nameof(SysCustomerOpenID.SysCustomerID)}=null where {nameof(SysCustomerOpenID.unionid)}='{currentOpenID.unionid.ExClearSql()}' and {nameof(SysCustomerOpenID.SysStoreID)}={currentOpenID.SysStoreID}";
                db.Database.ExExecuteSqlCommand(sql);
                CurrentOpenID.SysCustomerID = null;
                SetCurrentOpenID(WechatToken, CurrentOpenID);

                SetCurrentCustomer(Token, null);
            }
            else
            {
                UnBind(db);
            }
        }

        #endregion

        #region 模拟登录

        private static object _sync = new object();

        /// <summary>
        /// PC端调用的
        /// 模拟登录的cookie值
        /// </summary>
        /// <returns></returns>
        public AjaxResult<string> GetMobileCookie()
        {
            var store = PcLoginedBll.CurrentStore;
            if (store == null)
            {
                return AjaxResult<string>.ErrorResult("登录信息错误,请联系管理员");
            }
            lock (_sync)
            {
                using var db = Db;
                using var tran = db.Database.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted);
                int sysStoreID = store.GetParentID();
                string openid = "SysStoreDemo_" + sysStoreID;
                var has = db.SysCustomerOpenID.AsNoTracking().Any(m =>
                    m.EnumOpenIDType == EnumOpenIDType.微信公众号 && m.OpenID == openid && m.SysStoreID == sysStoreID);
                if (has == false)
                {
                    var dbAdd = Db;
                    SysCustomerOpenID testOpenID = new SysCustomerOpenID()
                    {
                        CreateDate = DateTime.Now,
                        EnumOpenIDType = EnumOpenIDType.微信公众号,
                        headimgurl = String.Empty,
                        ID = 0,
                        nickname = "模拟微信用户",
                        OpenID = openid,
                        Remark = "",
                        session_Key = null,
                        SysCustomer = null,
                        SysCustomerID = null,
                        SysStoreID = sysStoreID,
                        SysStore = null,
                        unionid = openid,
                        UpdateDate = DateTime.Now,
                        WechatToken = null,
                        WxJson = null,
                    };
                    dbAdd.SysCustomerOpenID.Add(testOpenID);
                    dbAdd.SaveChanges();
                }
                var userInfo = new Senparc.Weixin.Open.OAuthAPIs.OAuthUserInfo();
                userInfo.openid = openid;
                var tokenAr = GetWechatToken(userInfo, EnumOpenIDType.微信公众号, null, null, false);
                if (tokenAr.Success == false)
                {
                    return AjaxResult<string>.ErrorResult(tokenAr.Message);
                }
                if (tokenAr.Result.Count == 0)
                {
                    return AjaxResult<string>.ErrorResult("生成Token失败!");
                }

                var resultString = tokenAr.Result[0].ExToJson();
                return AjaxResult<string>.SuccessResult(resultString);
            }
        }

        #endregion
    }
}
